#ifndef __HOST_2_IP__
#define __HOST_2_IP__

#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <string.h>
#if defined(__APPLE__)
#include <netinet/in.h>
#include "mygetaddrinfo/mygetaddrinfo.h"
#elif defined(linux)
#include "mygetaddrinfo/mygetaddrinfo.h"
#endif

#ifdef WIN32
#define win_dump_error(fmt, ...) do { \
    int _errer_no = GetLastError(); \
    char _local_msg[1025]; memset(_local_msg, 0, 1025); \
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, _errer_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &_local_msg, sizeof(_local_msg), NULL); \
    LOGERR(fmt" [%d %s]\n", ##__VA_ARGS__, _errer_no, _local_msg); \
} while(0)
#endif

static inline int host_to_ipstr(const char *host, char *output, int buf_size)
{
    int ret = -1;
#if defined(linux) || defined(__APPLE__)
    struct addrinfo *result = NULL;
    struct addrinfo hints;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_INET; //AF_UNSPEC;    /* Allow IPv4 or IPv6 */
    hints.ai_socktype = SOCK_STREAM;
    int s = muslgetaddrinfo(host, NULL, &hints, &result); if (s) { LOGINF("GETADDRINFO return %d ERROR [%s]\n", s, gai_strerror(s)); return -1; }
    if (result == NULL) { LOGINF("GETADDRINFO ERROR [%s]\n", gai_strerror(s)); return -1; }
    struct sockaddr_in *addr = (struct sockaddr_in *)result->ai_addr;
    if (inet_ntop(result->ai_family, &addr->sin_addr, output, buf_size) == NULL) { LOGERR("inet_ntop error\n"); } else { ret = 0; }
    if (result) muslfreeaddrinfo(result);
    return ret;
#else
    //int i = 1;
    struct addrinfo *result = NULL;
    struct addrinfo *ptr = NULL;
    struct addrinfo hints;

    struct sockaddr_in  *sockaddr_ipv4;
//    struct sockaddr_in6 *sockaddr_ipv6;
    LPSOCKADDR sockaddr_ip;

    char ipstringbuffer[46];
    DWORD ipbufferlength = 46;
    //--------------------------------
    // Setup the hints address info structure
    // which is passed to the getaddrinfo() function
    ZeroMemory( &hints, sizeof(hints) );
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    //--------------------------------
    // Call getaddrinfo(). If the call succeeds,
    // the result variable will hold a linked list
    // of addrinfo structures containing response
    // information
    int dwRetval;
    dwRetval = getaddrinfo(host, "0", &hints, &result);
    if ( dwRetval != 0 ) {
        win_dump_error("getaddrinfo failed with error: %d ", dwRetval);
        //WSACleanup();
        return 1;
    }

    //LLOG("getaddrinfo returned success\n");

    // Retrieve each address and print out the hex bytes
    for(ptr=result; ptr != NULL ;ptr=ptr->ai_next) {

        //LLOG("getaddrinfo response %d\n", i++);
        //LLOG("\tFlags: 0x%x\n", ptr->ai_flags);
        //LLOG("\tFamily: ");
        switch (ptr->ai_family) {
            case AF_UNSPEC:
                LOGERR("Unspecified\n");
                break;
            case AF_INET:
                //LLOG("AF_INET (IPv4)\n");
                sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
                snprintf(output, buf_size - 1, "%s", inet_ntoa(sockaddr_ipv4->sin_addr));
                output[buf_size - 1] = 0;
                ret = 0;
                break;
            case AF_INET6:
                //LLOG("AF_INET6 (IPv6)\n");
                // the InetNtop function is available on Windows Vista and later
                // sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
                // LLOG("\tIPv6 address %s\n",
                //    InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr, ipstringbuffer, 46) );

                // We use WSAAddressToString since it is supported on Windows XP and later
                sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
                // The buffer length is changed by each call to WSAAddresstoString
                // So we need to set it for each iteration through the loop for safety
                ipbufferlength = 46;
                INT iRetval;
                iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL, ipstringbuffer, &ipbufferlength );
                if (iRetval)
                {
                    LOGERR("WSAAddressToString failed with %u\n", WSAGetLastError() );
                }
                else    
                {
                    snprintf(output, buf_size - 1, "%s", ipstringbuffer);
                    output[buf_size - 1] = 0;
                    ret = 0;
                }
                break;
            case AF_NETBIOS:
                LOGERR("AF_NETBIOS (NetBIOS)\n");
                break;
            default:
                LOGERR("Other %d\n", ptr->ai_family);
                break;
        }
        //LLOG("\tCanonical name: %s\n", ptr->ai_canonname);
    }

    freeaddrinfo(result);
    return ret;
#endif
}

#endif

